<?php

/**
 * Implements a simple cache
 * 
 * @author Pablo
 * @since 10
 */
	
class BlgCache {
	protected $path;
	protected $duration;
	
	function __construct($path, $duration= 86400){	
		if(is_dir($path)){
			$this->path= add_trainling_slash($path, DIRECTORY_SEPARATOR);
		}
		else if(mkdir($path, '0755', true)){
			$this->path= add_trainling_slash($path, DIRECTORY_SEPARATOR);	
		}
		else{
			$this->path= FALSE;
		}
		
		$this->duration= $duration;
	}
	
	/**
	 * Get an associate array with file paths to a cached value
	 * @param String $key
	 * @return Array
	 * @author Pablo
	 * @since 1.0
	 */
	protected function file_names($key){
		if($this->is_enabled()){			
			return array(
				'cache'	=> $this->path.'blg_'.$key.'.cache',
				'info'	=> $this->path.'blg_'.$key.'.info'
			);
		}
		
		return FALSE;
	}
	
	/**
	 * Get info about a cached data
	 * @param String $key
	 * @return Mixed [Array|FALSE]
	 * @author Pablo
	 * @since 1.0
	 */
	public function get_info($key){
		$file= $this->file_names($key);

		if(file_exists($file['info']))
			return unserialize(file_get_contents($file['info']));
		else
			return FALSE;
	}
	
	/**
	 * Check if a cached data has expired
	 * @param String $key
	 * @return Boolean
	 * @author Pablo
	 * @since 1.0
	 */
	public function has_expired($key){
		$info= $this->get_info($key);
		
		if(FALSE!==$info){
			if($info['duration'] <= 0) return FALSE;
			return ( time() >= $info['time_cache_expires'] );
		}
			
		return TRUE;		
	}
	
	/**
	 * Returns the UNIX time when data was written in cache
	 * @param String $key
	 * @return Boolean
	 * @author Pablo
	 * @since 1.0
	 */
	public function time_written($key){
		$info= $this->get_info($key);
		
		if(FALSE!==$info)
			return $info['time_written'];
			
		return 0;		
	}	
	
	/**
	 * Get a cached data
	 * @param String $key
	 * @return Mixed
	 * @author Pablo
	 * @since 1.0
	 */
	protected function get_data($key){
		$file= $this->file_names($key);

		if(file_exists($file['cache']))
			return file_get_contents($file['cache']);
		else
			return FALSE;
	}
	
	/**
	 * Cache a value
	 * @param String $key
	 * @param Mixed $value
	 * @param int $duration Seconds of valid cache data before expired
	 * @return Boolean True in case of success, FALSE otherwise
	 * @author Pablo
	 * @since 1.0
	 */
	public function set($key, $value, $duration= NULL){
		//Get file names
		$file= $this->file_names($key);
		if($duration===NULL) $duration= $this->duration;
				
		//Write data
		try{
			$bytes= file_put_contents($file['cache'], $value, LOCK_EX);
			
			$time= time();
			$info= serialize(array(
				'key' => $key,
				'cache_file' => $file['cache'],
				'time_written' => $time,
				'duration' => $duration,
				'time_cache_expires' => $time+$duration,
				'bytes' => $bytes 				
			));
			
			file_put_contents($file['info'], $info, LOCK_EX);
		}
		catch(ErrorException $e){
			blg_log($e->getMessage());
			return FALSE;
		}	
		
	}
	
	/**
	 * Get a cached value
	 * @param String $key
	 * @return Mixed (String|NULL) Returns the value from the cache if it exists, NULL otherwise.
	 * @author Pablo
	 * @since 1.0
	 */
	public function get($key){
		if(!$this->has_expired($key)){
			return $this->get_data($key);
		}
		
		return FALSE;
	}
	
	/**
	 * Clean the entire cache
	 * @author Pablo
	 * @since 1.0
	 */
	public function reset(){ 
		if($this->is_enabled()){
			$d= dir($this->path);
			while(FALSE!==($entry= $d->read())){
				if($entry!="." && $entry!=".." && !is_dir($this->path.$entry))
					unlink($this->path.$entry);
			}
			$d->close();
			return TRUE;
		}				
		return FALSE;
	}
	
	/**
	 * Clean a cached value
	 * @param String $key
	 * @return Boolean
	 * @author PAblo
	 * @since 1.0
	 */
	public function clean($key){
		$file= $this->file_names($key);
		
		if(FALSE!==$file){
			if(is_file($file['info']))
				unlink($file['info']);
	
			if(is_file($file['cache']))
				unlink($file['cache']);
				
			return TRUE;
		}			
		
		return FALSE;
	}
	
	/**
	 * Tells if the cache is enabled or not
	 * @return Boolean
	 * @author Pablo
	 * @Since 1.0
	 */
	public function is_enabled(){
		return ($this->path!==FALSE);
	}
}